#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <libusb-1.0/libusb.h>

int main(void)
{
	int i;
	int err;
	int config;
	int interface;
	int endpoint;
	int num_devices;
	int config_num;
	int interface_num;
	int endpoint_num;
	int transferred;
	struct libusb_context *ctx;
	struct libusb_device *dev;
	struct libusb_device **device_list;
	struct libusb_config_descriptor *config_desc;
	const struct libusb_interface_descriptor *intf_desc;
	const struct libusb_endpoint_descriptor *endpoint_desc;
	struct libusb_device_handle *dev_handle;
	struct libusb_device_descriptor dev_desc;
	unsigned char buffer[16];
	
	printf("libusb test\r\n");
	
	dev_handle = NULL;
	
	//初始化libusb
	err = libusb_init(&ctx);
	if (err) {
		printf("libusb initialization failed: %s", libusb_strerror(err));
		return err;
	}
	
	//获取USB设备列表
	num_devices = libusb_get_device_list(ctx, &device_list);
	if (num_devices < 0) {
		printf("could not enumerate USB devices: %s", libusb_strerror(num_devices));
		libusb_exit(ctx);
		return num_devices;
	}
	
	//遍历USB设备列表
	for (i = 0; (i < num_devices) && (!dev_handle); i++) {
		dev = device_list[i];
		//获取设备描述符
		err = libusb_get_device_descriptor(dev, &dev_desc);
		if (err) {
			printf("could not get device descriptor for device %d: %s", i, libusb_strerror(err));
			continue;
		}
		
		//遍历配置描述符
		for (config = 0; (config < dev_desc.bNumConfigurations) && (!dev_handle); config++) {
			//获取配置描述符
			err = libusb_get_config_descriptor(dev, config, &config_desc);
			if (err) {
				printf("could not get configuration descriptor %d for device 0x%04x:0x%04x: %s",
						config, dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err));
				continue;
			}
			
			//遍历配置下面的接口
			for (interface = 0; (interface < config_desc->bNumInterfaces) && (!dev_handle); interface++) {
				intf_desc = &config_desc->interface[interface].altsetting[0];
				
				//是否是USB鼠标设备
				if (intf_desc->bInterfaceClass != 3 || intf_desc->bInterfaceProtocol != 2)
					continue;
				printf("find USB mouse ok\n");
				
				//遍历端点
				for (endpoint = 0; (endpoint < intf_desc->bNumEndpoints) && (!dev_handle); endpoint++) {
					endpoint_desc = &intf_desc->endpoint[endpoint];
					
					//检查是否是中断输入端点
					if (((endpoint_desc->bmAttributes & 0x03) == LIBUSB_TRANSFER_TYPE_INTERRUPT) || \
						((endpoint_desc->bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN)) {
						//打开这个USB设备
						err = libusb_open(dev, &dev_handle);
						if (err) {
							libusb_free_config_descriptor(config_desc);
							libusb_free_device_list(device_list, 1);
							libusb_exit(ctx);
							printf("failed to open usb mouse\n");
							return err;
						}
						printf("libusb_open ok\n");
						
						//记录USB设备输入端点
						endpoint_num = endpoint_desc->bEndpointAddress;
					}
				}
				
				if (dev_handle) {
					//记录此接口的接口编号
					interface_num = intf_desc->bInterfaceNumber;
				}
			}
			
			if (dev_handle) {
				//记录此配置的配置编号
				config_num = config_desc->bConfigurationValue;
			}
			
			//释放配置描述符
			libusb_free_config_descriptor(config_desc);
		}
	}
	
	//释放设备列表
	libusb_free_device_list(device_list, 1);
	
	//没有找到USB设备设备
	if (!dev_handle) {
		//退出libusb
		libusb_exit(ctx);
		printf("find USB mouse failed\n");
		return -1;
	}
	
	//认领接口
	libusb_set_auto_detach_kernel_driver(dev_handle, 1);
	err = libusb_claim_interface(dev_handle, interface_num);
	if (err) {
		printf("failed to libusb_claim_interface\n");
		return err;
	}
	printf("libusb_claim_interface ok\n");
	
	while (1)
	{
		err = libusb_interrupt_transfer(dev_handle, endpoint_num, buffer, 16, &transferred, 5000);
		if (!err) {
			/* parser data */
			for (i = 0; i < transferred; i++)
			{
				printf("%02x ", buffer[i]);
			}
			printf("\n");
		}
		else if (err == LIBUSB_ERROR_TIMEOUT){
			printf("libusb_interrupt_transfer timout\n");
		}
		else {
			printf("libusb_interrupt_transfer err : %d\n", err);
		}
	}
	
	/* libusb_close */
	libusb_release_interface(dev_handle, interface_num);
	libusb_close(dev_handle);
	libusb_exit(ctx);
	return 0;
}
